/**
 *
 * © Bahadir Zeren 2011
 * bzeren@gmail.com
 * No warranties, express or implied, are made for this program.
 *
 */

package org.baatar.remoting.service;

import org.apache.log4j.Logger;
import org.baatar.net.tcp.TCPService;

/**
 * The main facade class which encapsulates TCP service, ImplementorTCPBridge
 * and Implementor classes together.
 * 
 * @see TCPService
 * @see ImplementorTCPBridge
 * @see IImplementor
 * 
 * @author Ba
 */
public class RemotingService {

    private TCPService tcpService = null;
    private IImplementor implementor = null;

    private RemotingServiceListener remotingServiceListener = null;

    private RemotingServiceInfo remotingServiceInfo = null;

    private boolean initialized = false;
    private boolean started = false;

    private Logger logger = null;

    /**
     * Constructor of the RemotingService class.
     * 
     * @param tcpService the TCPService object to set.
     * @param implementor the IImplementor object to set.
     */
    public RemotingService(TCPService tcpService,
                            IImplementor implementor) {
        this.tcpService = tcpService;
        this.tcpService.setThreadName(implementor.getClass().getSimpleName());
        this.implementor = implementor;
    }

    /**
     * Constructor of the RemotingService class.
     * 
     * @param implementor the IImplementor object to set.
     * @param listenerPortNr port number of the TCPService object to be created.
     */
    public RemotingService(IImplementor implementor, int listenerPortNr) throws Exception {
        this.tcpService = new TCPService(new ImplementorTCPBridge(implementor));
        this.tcpService.setThreadName(implementor.getClass().getSimpleName());
        this.tcpService.setListenerPort(listenerPortNr);
        this.implementor = implementor;
    }

    /**
     * Constructor of the RemotingService class.
     * 
     * @param implementor the IImplementor object to set.
     */
    public RemotingService(IImplementor implementor) throws Exception {
        this.tcpService = new TCPService(new ImplementorTCPBridge(implementor));
        this.tcpService.setThreadName(implementor.getClass().getSimpleName());
        this.implementor = implementor;
    }

    /**
     * Initializes remoting service facade.
     * Initializes TCPService and IImplementor objects together.
     * 
     * @return boolean true if initialization is succesfull.
     * 
     * @throws Exception if an exception occurs.
     */
    public boolean initializeService() throws Exception {
        if (!initialized) {
            try {

                if (tcpService.initialize()) {

                    remotingServiceInfo = new RemotingServiceInfo(tcpService.getListenerPort(),
                                                                    implementor.getClass().getSimpleName());

                    if (implementor.initialize()) {
                        implementor.setRemotingService(this);
                        initialized = true;
                    } else
                        finalizeService();

                } else
                    finalizeService();

            } catch (Exception ex) {
                if (logger != null)
                    logger.error(ex.getMessage());
                finalizeService();
            }
        }
        return initialized;
    }

    /**
     * Finalizes remoting service facade.
     * Finalizes TCPService and IImplementor objects together.
     */
    public void finalizeService() {
        try {
            if (tcpService != null) {
                tcpService.uninitialize();
            }
            if (implementor != null) {
                implementor.uninitialize();
            }
            if (logger != null) {
                logger.removeAllAppenders();
                logger = null;
            }
            initialized = false;
        } catch (Exception ex) {
        }
    }

    /**
     * Starts remoting service facade.
     * Starts TCPService and IImplementor objects together.
     * 
     * @throws Exception if an exception occurs.
     */
    public boolean startService() {
        if (!started) {
            try {
                if (tcpService.start()) {
                    if ((implementor == null) ||
                            implementor.start()) {

                        started = (remotingServiceListener == null) ||
                                    remotingServiceListener.OnRemotingServiceStart();

                        if (!started)
                            stopService();
                        else
                            logger.info("Remoting Service [" + remotingServiceInfo + "] is started.");
                    }
                    else
                        stopService();
                }
                else
                    stopService();
            } catch (Exception ex) {
                logger.error(ex.getMessage());
                stopService();
            }
        }
        return started;
    }

    /**
     * Stops remoting service facade.
     * Stops TCPService and IImplementor objects together.
     * 
     * @throws Exception if an exception occurs.
     */
    public void stopService() {
        try {
            if (tcpService != null) {
                tcpService.stop();
            }
            if (implementor != null) {
                implementor.stop();
            }
            started = false;
            logger.info("Remoting Service [" + remotingServiceInfo + "] is stopped.");
        } catch (Exception ex) {
        }
    }

    /**
     * Returns TCPService object of the remoting service object.
     * 
     * @return TCPService tcp service instance of the remoting service object.
     */
    public TCPService getTcpService() {
        return tcpService;
    }

    /**
     * Returns IImplementor object of the remoting service object.
     * 
     * @return IImplementor implementor instance of the remoting service object.
     */
    public IImplementor getImplementor() {
        return implementor;
    }

    /**
     * Returns Logger object of the remoting service object.
     * 
     * @return Logger logger instance of the remoting service object.
     */
    public Logger getLogger() {
        return logger;
    }

    /**
     * Returns initialization status of the remote service object.
     * 
     * @return boolean true if the remote service object is initialized.
     */
    public boolean isInitialized() {
        return initialized;
    }

    /**
     * Returns running status of the remote service object.
     * 
     * @return boolean true if the remote service object is running.
     */
    public boolean isStarted() {
        return started;
    }

    /**
     * Returns information about the remote service object.
     * 
     * @return RemotingServiceInfo of the remote service object.
     */
    public RemotingServiceInfo getRemotingServiceInfo() {
        return remotingServiceInfo;
    }

    /**
     * Returns RemotingServiceListener object of the remote service object.
     * 
     * @return RemotingServiceListener of the remote service object.
     */
    public RemotingServiceListener getRemotingServiceListener() {
        return remotingServiceListener;
    }

    /**
     * @param remotingServiceListener the remotingServiceListener to set
     */
    public void setRemotingServiceListener(RemotingServiceListener remotingServiceListener) {
        this.remotingServiceListener = remotingServiceListener;
    }

    /**
     * @param logger the logger to set
     */
    public void setLogger(Logger logger) {
        this.logger = logger;
        this.tcpService.setLogger(logger);
        this.implementor.setLogger(logger);
    }
}
